package com.syl.starter.itools.framework.utils;

import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonEncoding;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator;
import com.syl.starter.itools.base.utils.CloseUtils;
import com.syl.starter.itools.base.utils.LogUtils;
import com.syl.starter.itools.common.utils.StringUtils;
import com.syl.starter.itools.framework.utils.help.BaseXMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.StringWriter;

/**
 * xml工具类
 * 注意：如果bean中有List 时需要使用在字段上加 JacksonXmlElementWrapper 注解
 *
 * @author syl
 * @create 2018-09-07 10:54
 **/
@SuppressWarnings("unchecked")
public class XmlUtils extends BaseXMapper {
    private static Logger LOG = LoggerFactory.getLogger(XmlUtils.class);

    /**
     * 把对象转换为xml 字符串
     * @param object
     * @return
     */
    public static String toXml(Object object){
        return toXml(object, null);
    }

    /**
     * 把对象转换为xml 字符串
     * @param object 对象
     * @param strategy 转换策略
     * @return
     */
    public static String toXml(Object object, JsonInclude.Include strategy){
        return xToString(new XmlMapper(), object, strategy);
    }

    /**
     * 把xml文本转换为json
     * @param xml
     * @return
     */
    public static String toJson(String xml){
        if(StringUtils.isEmpty(xml))
            return null;
        StringWriter w = new StringWriter();
        JsonParser jp = null;
        JsonGenerator jg = null;
        try {
            XmlMapper xmlMapper = new XmlMapper();
            ObjectMapper mapper = JsonUtils.getObjectMapper(true);
            jp = xmlMapper.getFactory().createParser(xml);
            jg = mapper.getFactory().createGenerator(w);
            while (jp.nextToken() != null) {
                jg.copyCurrentEvent(jp);
            }
            return w.toString();
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            CloseUtils.closeAll(jp,jg);
        }
        return null;
    }

    /**
     * 从输入流中把xml转换为java bean 默认非严格模式
     * @param inputStream
     * @param cz
     * @param <T>
     * @return
     */
    public static <T> T fromXml(InputStream inputStream, Class<T> cz){
        return fromXml(inputStream, cz, false);
    }

    /**
     * 从输入流中把xml转换为java bean
     * @param inputStream
     * @param cz
     * @param <T>
     * @param strict 是否严格模式
     * @return
     */
    public static <T> T fromXml(InputStream inputStream, Class<T> cz, boolean strict){
        if(inputStream == null)
            return null;
        XmlMapper mapper = getXmlMapper(strict);
        try {
            return mapper.readValue(inputStream,cz);
        } catch (IOException e) {
            LogUtils.error(LOG,"转换失败  ", e);
            return null;
        }
    }

    /**
     * 把xml转换为java bean 默认非严格模式
     * @param xml
     * @param cz
     * @param <T>
     * @return
     */
    public static <T> T fromXml(String xml, Class<T> cz){
        return fromXml(xml, cz,false);
    }

    /**
     * 把xml转换为java对象
     * @param xml
     * @param cz
     * @param <T>
     * @param strict 是否严格模式
     * @return
     */
    public static <T> T fromXml(String xml, Class<T> cz, boolean strict){
        if(StringUtils.isEmpty(xml))
            return null;
        XmlMapper mapper = getXmlMapper(strict);
        try {
            return mapper.readValue(xml, cz);
        } catch (IOException e) {
            LogUtils.error(LOG,"转换失败  xml 为 {}", e, xml);
        }
        return null;
    }

    private static XmlMapper getXmlMapper(boolean strict){
        XmlMapper mapper = new XmlMapper();
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, strict);
        mapper.configure(DeserializationFeature.WRAP_EXCEPTIONS, false);
        return mapper;
    }

    /**
     * 设置xml到输出流中 默认以UTF-8输出
     * @param out
     * @param xml
     * @return
     */
    public static boolean outputStream(OutputStream out,String xml){
        if(out == null || xml == null)
            return false;
        if(StringUtils.isEmpty(xml))
            return false;
        try {
            XmlMapper xmlMapper = new XmlMapper();
            xmlMapper.writeValue(out,xml);
            return true;
        } catch (IOException e) {
            LogUtils.error(LOG, "输入输出流异常", e);
            return false;
        }
    }

    /**
     * 设置xml到输出流中
     * @param out
     * @param xml
     * @param enc 编码
     * @return
     */
    public static boolean outputStream(OutputStream out, String xml, JsonEncoding enc){
        if(out == null || xml == null)
            return false;
        if(StringUtils.isEmpty(xml))
            return false;
        if(enc == null)
            return outputStream(out, xml);
        try {
            XmlMapper xmlMapper = new XmlMapper();
            ToXmlGenerator generator = xmlMapper.getFactory().createGenerator(out, enc);
            xmlMapper.writeValue(generator,xml);
            return true;
        } catch (IOException e) {
            LogUtils.error(LOG, "输入输出流异常", e);
            return false;
        }
    }

}
